package com.physics.mps.module.abaqus;

import cn.hutool.core.collection.CollectionUtil;
import com.physics.mps.entity.vo.*;
import com.physics.mps.entity.vo.*;
import com.physics.mps.entity.vo.result.AbaqusEmagParam;
import com.physics.mps.module.util.PyUtils;
import lombok.Setter;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Abaqus计算模块：电磁分析
 */
@Setter
public class AbaqusEmagHandler extends AbstractAbaqusComputeHandler {

    /**
     * 对流换热设置参数
     */
    private List<InteractionVo> interactions;

    /**
     * 边界条件参数
     */
    private List<AbaqusBoundaryVo> boundaryVos;

    /**
     * 电磁分析分析步参数
     */
    private AbaqusEmagStepVo emagStepVo;

    private List<AbaqusTieVo> tieVos;


    public AbaqusEmagHandler setAbaqusComputeParam(AbaqusComputeParam abaqusEmagParam) {
        this.abaqusComputeParam = abaqusEmagParam;
        if (abaqusEmagParam instanceof AbaqusEmagParam) {
            AbaqusEmagParam specificParam = (AbaqusEmagParam) abaqusEmagParam;

            // 然后使用specificParam进行后续的操作...

            this.parts = specificParam.getParts();

            this.partNames = specificParam.getPartNames();

            this.meshVo = specificParam.getMeshVo();

            this.jobVo = specificParam.getJobVo();

            //this.jobVo.setVariableLabel("NT11");

            //this.jobVo.setOutputPosition("NODAL");

            this.interactions = specificParam.getInteractions();

            this.boundaryVos = specificParam.getBoundaryVos();

            this.emagStepVo = specificParam.getEmagStepVo();

            super.tieVos = specificParam.getTieVos();

            this.board = specificParam.getBoard();

            this.stpPath = specificParam.getStpPath();

            this.setComputeParam = true;
        }


        return this;
    }

    @Override
    public void createStepImpl(StringBuilder builder) {
        builder
                .append(this.createMdbModelsCommand("Model-1"))
                .append(".EmagTimeHarmonicStep(name='Step-1', previous='Initial'")
                .append(", frequencyRange=((")
                .append(emagStepVo.getLowerFrequency()).append(", ")
                .append(emagStepVo.getUpperFrequency()).append(", ")
                .append(emagStepVo.getNumEigen())
                .append("), ))").append(PyUtils.WRAP);
    }


    @Override
    public void createStepAndFieldImpl(StringBuilder builder) {
        //5.合并所有部件
        builder.append(this.createMergePartCommand());

        //6.创建分析步
        builder.append(this.createStep());

        //6.1.输出结果设置
        builder.append(this.createOutputCommand());

        //7.创建边界条件
        builder.append(this.createBoundaryCommand());

        //8.创建圆柱坐标系
        builder.append(this.createCylindricalCoordinateCommand());

        //9.施加电流密度
        builder.append(this.createInteractionCommand());

        Set<String> nPartNames = new HashSet<>();
        nPartNames.add("domain");
        partNames = nPartNames;
    }

    // ~ Variable & Constant
    // ========================================================================================================


    // ~ Public method
    // ========================================================================================================


    // ~ Override method
    // ========================================================================================================
    @Override
    public void createBoundaryCommandImpl(StringBuilder builder) {
        /*
        a = mdb.models['Model-1'].rootAssembly
        s1 = a.instances['domain-1'].faces
        side1Faces1 = s1.findAt(((-49.962094, -1.946577, 8.333333), ))
        region = regionToolset.Region(side1Faces=side1Faces1)
        mdb.models['Model-1'].MagneticVectorPotentialBC(name='BC-1', createStepName='Step-1', region=region, component1=0+0j, component2=0+0j, component3=0+0j, distributionType=UNIFORM, localCsys=None)
         */
        builder.append("a = ")
                .append(this.createMdbModelsCommand("Model-1"))
                .append(".rootAssembly")
                .append(PyUtils.WRAP);
        builder.append("s1 = a.instances['domain-1'].faces").append(PyUtils.WRAP);
        int i = 1;
        for (AbaqusBoundaryVo boundaryVo : boundaryVos) {
            String[] coordinate = boundaryVo.getCoordinate().get(0);
            List<String> magneticVectorPotential = boundaryVo.getMagneticVectorPotential();
            builder.append("side1Faces1 = s1.findAt(((")
                    .append(coordinate[0]).append(", ").append(coordinate[1]).append(", ").append(coordinate[2])
                    .append("), ))").append(PyUtils.WRAP);
            builder.append("region = regionToolset.Region(side1Faces=side1Faces1)").append(PyUtils.WRAP);
            builder.append(this.createMdbModelsCommand("Model-1"))
                    .append(".MagneticVectorPotentialBC(name='BC-").append(i++)
                    .append("', createStepName='Step-1', region=region")
                    .append(", component1=").append(magneticVectorPotential.get(0)).append("+").append(magneticVectorPotential.get(1))
                    .append("j, component2=").append(magneticVectorPotential.get(2)).append("+").append(magneticVectorPotential.get(3))
                    .append("j, component3=").append(magneticVectorPotential.get(4)).append("+").append(magneticVectorPotential.get(5))
                    .append("j, distributionType=UNIFORM, localCsys=None)")
                    .append(PyUtils.WRAP);
        }
    }

    @Override
    public void createOutputCommandImpl(StringBuilder builder) {
        /*
        mdb.models['Model-1'].FieldOutputRequest(name='F-Output-1', createStepName='Step-1', variables=('EMB', 'EMH', 'EME'))
         */
        builder.append(this.createMdbModelsCommand("Model-1"))
                .append(".FieldOutputRequest(")
                .append("name='F-Output-1'")
                .append(", createStepName='Step-1'")
                .append(", variables=('EMB', 'EMH', 'EME'))")
                .append(PyUtils.WRAP);
        builder.append("a.regenerate()").append(PyUtils.WRAP);
    }

    @Override
    public void createElemTypeCommandImpl(StringBuilder builder) {

    }

    @Override
    public void createExportCommandImpl(StringBuilder builder) {
        builder.append("def loopAndCompare(instance_name, max_val, min_val):").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("field_variable = lastFrame.fieldOutputs['NT11'].getSubset(region=instance[instance_name])").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("fieldValues = field_variable.values").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("for v in fieldValues:").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("if (v.data > max_val):").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(3)).append("max_val = v.data").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("if (v.data < min_val):").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(3)).append("min_val = v.data").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("return max_val, min_val").append(PyUtils.WRAP);

        builder.append("from odbAccess import openOdb").append(PyUtils.WRAP);
        builder.append("from textRepr import *").append(PyUtils.WRAP);
        builder.append("my_odb = openOdb(r\"").append(this.workDir).append("\\\\").append(jobVo.getJobName()).append(".odb\")").append(PyUtils.WRAP);
        builder.append("file = open('").append(this.workDir).append("\\\\PNG\\\\").append(this.jobVo.getJobName()).append(".txt', 'w')").append(PyUtils.WRAP);
        builder.append("lastFrame = my_odb.steps['Step-1'].frames[-1]").append(PyUtils.WRAP);
        builder.append("len = ").append(partNames.size()).append(PyUtils.WRAP);
        builder.append("instance = my_odb.rootAssembly.instances").append(PyUtils.WRAP);

        builder.append("instance_name = 'COMPOUND'").append(PyUtils.WRAP);
        builder.append("field_variable=lastFrame.fieldOutputs['NT11'].getSubset(region = instance[instance_name])").append(PyUtils.WRAP);
        builder.append("fieldValues=field_variable.values").append(PyUtils.WRAP);
        builder.append("val=field_variable.values[0].data").append(PyUtils.WRAP);
        builder.append("max_val, min_val = loopAndCompare(instance_name, val, val)").append(PyUtils.WRAP);
        builder.append("file.write(instance_name + ':max_val:' + str(max_val) + '\\n')").append(PyUtils.WRAP);
        builder.append("file.write(instance_name + ':min_val:' + str(min_val) + '\\n')").append(PyUtils.WRAP);
        builder.append("for i in range(1, len) :").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("instance_name = 'COMPOUND-' + str(i)").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("if instance_name != \"").append(this.board).append("\" :").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("max_val, min_val = loopAndCompare(instance_name, max_val, min_val)").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("file.write(instance_name + ':max_val:' + str(max_val) + '\\n')").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("file.write(instance_name + ':min_val:' + str(min_val) + '\\n')").append(PyUtils.WRAP);
        builder.append("instance_name = \"").append(this.board).append("\"").append(PyUtils.WRAP);
        builder.append("field_variable=lastFrame.fieldOutputs['NT11'].getSubset(region = instance[instance_name])").append(PyUtils.WRAP);
        builder.append("fieldValues=field_variable.values").append(PyUtils.WRAP);
        builder.append("val=field_variable.values[0].data").append(PyUtils.WRAP);
        builder.append("max_val2, min_val2 = loopAndCompare(instance_name, val, val)").append(PyUtils.WRAP);
        builder.append("file.write('BOARD:max_val:' + str(max_val2) + '\\n')").append(PyUtils.WRAP);
        builder.append("file.write('BOARD:min_val:' + str(min_val2) + '\\n')").append(PyUtils.WRAP);
        builder.append("file.close()").append(PyUtils.WRAP);
    }

    // ~ Private method
    // ========================================================================================================


    private String createInteractionCommand() {
        if (CollectionUtil.isEmpty(interactions)) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        int num = 1;
        builder.append("c1 = a.instances['domain-1'].cells").append(PyUtils.WRAP);
        for (InteractionVo interaction : interactions) {
            String[] coordinate = interaction.getCoordinates().get(0);
            String[] amperDensity = interaction.getAmperDensity();

            builder.append("cells1 = c1.findAt(((")
                    .append(coordinate[0]).append(", ")
                    .append(coordinate[1]).append(", ")
                    .append(coordinate[2]).append("), ))")
                    .append(PyUtils.WRAP);
            builder.append("region = regionToolset.Region(cells=cells1)").append(PyUtils.WRAP);
            builder.append("datum=a.datum.values()[1]").append(PyUtils.WRAP);
            builder.append(this.createMdbModelsCommand("Model-1"))
                    .append(".BodyCurrentDensity(name='Load-").append(num++)
                    .append("',createStepName='Step-1', region=region")
                    .append(", comp1=").append(amperDensity[0]).append("+").append(amperDensity[1])
                    .append("j, comp2=").append(amperDensity[2]).append("+").append(amperDensity[3])
                    .append("j, comp3=").append(amperDensity[4]).append("+").append(amperDensity[5])
                    .append("j, amplitude=UNSET, distributionType=UNIFORM, localCsys=datum)")
                    .append(PyUtils.WRAP);
        }
        return builder.toString();
    }

    private String createMergePartCommand() {
        StringBuilder builder = new StringBuilder();

        builder
                .append(this.createMdbModelsCommand("Model-1"))
                .append(".rootAssembly").append(PyUtils.WRAP);
        builder
                .append("a.InstanceFromBooleanMerge(name='domain', instances=(a.instances.values()), ")
                .append("keepIntersections=ON, originalInstances=SUPPRESS,domain=GEOMETRY)")
                .append(PyUtils.WRAP);
        return builder.toString();
    }

    private String createCylindricalCoordinateCommand() {
        StringBuilder builder = new StringBuilder();

        List<String> origin = emagStepVo.getOrigin();
        List<String> point1 = emagStepVo.getPoint1();
        List<String> point2 = emagStepVo.getPoint2();
        builder
                .append("a.DatumCsysByThreePoints(name='Datum csys-cylinder', coordSysType=CYLINDRICAL")
                .append(", origin=(").append(origin.get(0)).append(", ").append(origin.get(1)).append(", ").append(origin.get(2))
                .append("), point1=(").append(point1.get(0)).append(", ").append(point1.get(1)).append(", ").append(point1.get(2))
                .append("), point2=(").append(point2.get(0)).append(", ").append(point2.get(1)).append(", ").append(point2.get(2))
                .append("))").append(PyUtils.WRAP);
        return builder.toString();
    }
    // ~ Autowired
    // ========================================================================================================


}
